﻿using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace microp11.rf.tx141bv2
{
    static class Consts
    {
        public static int PLUS_LO_HISTOGRAM = 0;
        public static int PLUS_HI_HISTOGRAM = 1;
        public static int THRESHOLD = 100;
    }

    class WaveBlock
    {
        private List<short> samples;
        private double threshold;
        private int[] bins;
        private short maxValue;
        private double decibels;
        private int histogramType;

        public WaveBlock()
        {
            samples = new List<short>();
            threshold = -1.0;
            bins = new int[10];
            maxValue = 0;
            histogramType = Consts.PLUS_LO_HISTOGRAM;
        }

        public List<short> Samples
        {
            get { return samples; }
            set { samples = value; }
        }

        public int[] Bins
        {
            get { return bins; }
            set { bins = value; }
        }

        public int HistogramType
        {
            get { return histogramType; }
            set
            {
                histogramType = value;
                //force processing
                ProcessingBlock();
            }
        }
        
        public double Threshold
        {
            get
            {
               if (threshold < 0)
               {
                   ProcessingBlock();
               }
                
                return threshold;
            }
        }

        public int Size
        {
            get
            {
                if (threshold < 0)
                {
                    ProcessingBlock();
                } 
                
                return samples.Count;
            }
        }

        public short MaxValue
        {
            get
            {
               if (threshold < 0)
               {
                   ProcessingBlock();
               }
                
                return maxValue;
            }
        }

        public double Decibels
        {
            get
            {
                if (threshold < 0)
                {
                    ProcessingBlock();
                }

                return decibels;
            }
        }        

        private void ProcessingBlock()
        {
            double sum_p2;

            Array.Clear(bins, 0, 10);

            if (histogramType == Consts.PLUS_HI_HISTOGRAM)
            {
                sum_p2 = 0.0;

                if (samples.Count == 0)
                {
                    Array.Clear(bins, 0, 10);
                }

                for (int i = 0; i < samples.Count; i++)
                {
                    if (samples[i] >= 0)
                    {
                        //0.00 - 0.1
                        if ((double)samples[i] < (0.1 * 32768))
                        {
                            bins[0]++;
                        }
                        else if ((double)samples[i] < (0.2 * 32768))
                        {
                            bins[1]++;
                        }
                        else if ((double)samples[i] < (0.3 * 32768))
                        {
                            bins[2]++;
                        }
                        else if ((double)samples[i] < (0.4 * 32768))
                        {
                            bins[3]++;
                        }
                        else if ((double)samples[i] < (0.5 * 32768))
                        {
                            bins[4]++;
                        }
                        else if ((double)samples[i] < (0.6 * 32768))
                        {
                            bins[5]++;
                        }
                        else if ((double)samples[i] < (0.7 * 32768))
                        {
                            bins[6]++;
                        }
                        else if ((double)samples[i] < (0.8 * 32768))
                        {
                            bins[7]++;
                        }
                        else if ((double)samples[i] < (0.9 * 32768))
                        {
                            bins[8]++;
                        }
                        //0.9 - 1.00
                        else
                        {
                            bins[9]++;
                        }
                    }

                    maxValue = Math.Max(maxValue, samples[i]);

                    double sample = samples[i] / 32768.0;
                    sum_p2 += (sample * sample);

                }

                int binsX = 0;
                for (int i = 1; i < bins.Length-1; i++)
                {
                    binsX += bins[i];
                }
                threshold = binsX / 8 * 1.33;
            }
            else
            {
                sum_p2 = 0.0;
                
                //compute positive quick histogram coeficient
                if (samples.Count == 0)
                {
                    bins[0] = 0;
                    bins[1] = 0;
                    bins[2] = 0;
                }

                for (int i = 0; i < samples.Count; i++)
                {
                    if (samples[i] >= 0)
                    {
                        //0.00 - 0.1
                        if ((double)samples[i] < (0.1 * 32768))
                        {
                            bins[0]++;
                        }
                        //0.1 - 0.9
                        else if ((double)samples[i] < (0.9 * 32768))
                        {
                            bins[1]++;
                        }
                        //0.9 - 1.00
                        else
                        {
                            bins[2]++;
                        }
                    }

                    maxValue = Math.Max(maxValue, samples[i]);

                    double sample = samples[i] / 32768.0;
                    sum_p2 += (sample * sample);

                }

                threshold = bins[1] / 2 * 1.33;
            }

            double rms = Math.Sqrt(sum_p2 / (samples.Count / 2));
            decibels = 20 * Math.Log10(rms);

            if (histogramType == Consts.PLUS_HI_HISTOGRAM)
            {
                for (int i = 0; i < bins.Length; i++)
                {
                    Debug.WriteLine("bin[{0}] {1}", i, bins[i]);
                }
                Debug.WriteLine("{0:mm:ss:ffff} decibel: {1:0.00}, coef: {2}", DateTime.Now, decibels, threshold);
            }
        }

        internal void Clear()
        {
            samples.Clear();
            threshold = -1.0;
            maxValue = 0;
            histogramType = Consts.PLUS_LO_HISTOGRAM;
        }
    }
}
